package rpc.bootstrap.spring;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.core.env.Environment;
import rpc.core.RefererProxyFactory;
import rpc.utils.ExceptionUtils;
import rpc.utils.ReflectionUtils;

/*********
 *
 *
 *@author 197
 *@date 2020/6/18 20:42
 *
 **/


public class BeanPostProcessor implements BeanFactoryPostProcessor {

  private static final Logger logger = LoggerFactory.getLogger(BeanPostProcessor.class);
  protected List<? extends Class<?>> refersList;

  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory0)
      throws BeansException {
    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) beanFactory0;
    Environment environment = (Environment) beanFactory.getBean("environment");

    List<String> referers = new ArrayList<>();
    String interfaceName = environment.getProperty("rpc.referer.interfaceName");
    if (StringUtils.isNotBlank(interfaceName)) {
      referers.add(interfaceName);
    }
    int maxCount = Integer
        .parseInt(Objects.toString(environment.getProperty("rpc.referer.maxCount"), "100"));
    if (logger.isDebugEnabled()) {
      logger.debug("rpc.referer.maxCount {}", maxCount);
    }
    for (int i = 0; i < maxCount; i++) {
      String key = StringUtils.replace("rpc.referers[_].interfaceName", "_", String.valueOf(i));
      interfaceName = environment.getProperty(key);
      if (StringUtils.isBlank(interfaceName) && logger.isDebugEnabled()) {
        logger.debug("interfaceName  {}  is  null", key);
        break;
      }
      referers.add(interfaceName);
    }
    refersList = referers.stream().map(ReflectionUtils::getClass).collect(Collectors.toList());
    refersList.forEach(refererName -> initReferer(refererName, beanFactory));

  }

  private void initReferer(Class<?> interfaceClass, DefaultListableBeanFactory beanFactory) {
    try {
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(interfaceClass);
      GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
      definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
      definition.setBeanClass(RefererProxyFactory.class);
      definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
      // 注册bean名,一般为类名首字母小写
      String simpleName = interfaceClass.getSimpleName();
      beanFactory.registerBeanDefinition(simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1), definition);
    } catch (Exception e) {
      logger.error("createClass:{},msg:{}", e.getClass().getName(), e.getMessage());
      logger.error("exception:{} stackTrace:{}", e.getMessage(), ExceptionUtils.getTrace(e));
    }
  }

  public List<? extends Class<?>> getRefersList() {
    return refersList;
  }
}
